#include "png.h"

#define LAND_GRAPHICS_CORE

#include "init.h"

struct {
    LandGraphics* config;
    LandTextureBackend* backend;
}ctx = { 0 };

void
landInitTextureContext(
    LandGraphics* config, LandTextureBackend* backend) {
    ctx.config = config;
    ctx.backend = backend;
}

static void
freeTexture(LandRef* ref) {
    ctx.backend->freeTexture((LandTexture*)ref);
}

LAND_GRAPHICS_API LandTexture*
landNewTexture(unsigned width, unsigned height, LandColorFormat format) {
    size_t size = ctx.backend->sizeofTexture();
    LandTexture* tex = landNewRef(size, freeTexture);
    tex->width = width;
    tex->height = height;
    tex->format = format;
    tex->minFilter = LAND_TEXTURE_FILTER_LINEAR;
    tex->maxFilter = LAND_TEXTURE_FILTER_LINEAR;
    tex->sWrap = LAND_TEXTURE_WRAP_BORDER;
    tex->sWrap = LAND_TEXTURE_WRAP_BORDER;
    ctx.backend->newTexture(tex);
    return tex;
}

LAND_GRAPHICS_API LandTexture*
landNewPngTexture(const char* path) {
    FILE* f = fopen(path, "rb");
    if (!f) {
        return NULL;
    }
    unsigned char* image = NULL;
    png_int_32 width, height;

    png_structp png_ptr = png_create_read_struct(
        PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr) {
        fclose(f);
        return NULL;
    }
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        fclose(f);
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return NULL;
    }
    png_init_io(png_ptr, f);
    png_read_info(png_ptr, info_ptr);
    width = png_get_image_width(png_ptr, info_ptr);
    height = png_get_image_height(png_ptr, info_ptr);
    int bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    int color_type = png_get_color_type(png_ptr, info_ptr);
    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);
    if (bit_depth == 16)
        png_set_strip_16(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
        png_set_expand_gray_1_2_4_to_8(png_ptr);
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
        png_set_tRNS_to_alpha(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY 
        || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);
    png_read_update_info(png_ptr, info_ptr);
    png_bytep* rows = (png_bytep*)malloc(sizeof(png_bytep) * height);
    for (int y = 0; y < height; y++) {
        rows[y] = (png_byte*)malloc(png_get_rowbytes(png_ptr, info_ptr));
    }
    png_read_image(png_ptr, rows);
    image = malloc(width * height * 4); // Assuming 32-bit RGBA format
    for (int y = 0; y < height; y++) {
        png_bytep r = rows[y];
        for (int x = 0; x < width * 4; x += 4) {
            image[y * width * 4 + x] = r[x]; // Red
            image[y * width * 4 + x + 1] = r[x + 1]; // Green
            image[y * width * 4 + x + 2] = r[x + 2]; // Blue
            image[y * width * 4 + x + 3] = r[x + 3]; // Alpha
        }
        free(rows[y]);
    }
    free(rows);
    png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
    LandTexture* tex = landNewTexture(width, height, LAND_COLOR_RGBA);
    unsigned rect[] = { 0, 0, width, height };
    landUploadTexture(tex, LAND_COLOR_RGBA, rect, image);
    free(image);
    fclose(f);
    return tex;
}


LAND_GRAPHICS_API int
landUploadTexture(LandTexture* tex,
    int format, unsigned rect[4], const void* data){
    return ctx.backend->uploadPixel(tex, format, rect, data);
}

LAND_GRAPHICS_API void
landTextureFilter(LandTexture* tex,
    LandTexFilter minFilter, LandTexFilter maxFilter) {
    tex->minFilter = minFilter;
    tex->maxFilter = maxFilter;
    ctx.backend->setFilter(tex);
}
LAND_GRAPHICS_API void
landTextureWrap(LandTexture* tex,
    LandTexWrap sWrap, LandTexWrap tWrap) {
    tex->sWrap = sWrap;
    tex->tWrap;
    ctx.backend->setWrap(tex);
}
